
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Building Larger Apps - vue.js</title>
        <meta charset="utf-8">
        <meta name="description" content="Vue.js - Intuitive, Fast and Composable MVVM for building interactive interfaces.">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
        <link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Lato|Inconsolata' rel='stylesheet' type='text/css'>
        <link rel="icon" href="/images/logo.png" type="image/x-icon">
        <script>
            window.PAGE_TYPE = "guide"
        </script>
        <link rel="stylesheet" href="/css/page.css" type="text/css">
        <script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-46852172-1', 'vuejs.org');
  ga('send', 'pageview');
</script>
        <script src="/js/vue.min.js"></script><script src="https://cdn.jsdelivr.net/gh/shentao/vuejs-outdated-docs-modal@v1.3/prompt.min.js"></script>
    </head>
    <body>
        <div id="mobile-bar">
            <a class="menu-button"></a>
            <a class="logo" href="/"></a>
        </div>
        
            <div id="header">
    <a id="logo" href="/">
        <img src="/images/logo.png">
        <span>Vue.js</span>
    </a>
    <ul id="nav">
        <li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API Reference</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li><a href="https://github.com/yyx990803/vue" target="_blank" class="nav-link">GitHub</a></li>
    </ul>
</div>
            <div id="main">
                
                    
    <div class="sidebar">
    <ul class="main-menu">
        <li><a href="/guide/" class="nav-link current">Guide</a></li>
<li><a href="/api/" class="nav-link">API Reference</a></li>
<li><a href="/examples/" class="nav-link">Examples</a></li>
<li><a href="/blog/" class="nav-link">Blog</a></li>
<li><a href="https://github.com/yyx990803/vue" target="_blank" class="nav-link">GitHub</a></li>
    </ul>
    <div class="list">
        <h2>Guide</h2>
        <ul class="menu-root">
            
                <li><a href="/guide/installation.html" class="sidebar-link">Installation</a></li>
            
                <li><a href="/guide/index.html" class="sidebar-link">Getting Started</a></li>
            
                <li><a href="/guide/directives.html" class="sidebar-link">Directives</a></li>
            
                <li><a href="/guide/filters.html" class="sidebar-link">Filters</a></li>
            
                <li><a href="/guide/list.html" class="sidebar-link">Displaying a List</a></li>
            
                <li><a href="/guide/events.html" class="sidebar-link">Listening for Events</a></li>
            
                <li><a href="/guide/forms.html" class="sidebar-link">Handling Forms</a></li>
            
                <li><a href="/guide/computed.html" class="sidebar-link">Computed Properties</a></li>
            
                <li><a href="/guide/custom-directive.html" class="sidebar-link">Custom Directives</a></li>
            
                <li><a href="/guide/custom-filter.html" class="sidebar-link">Custom Filters</a></li>
            
                <li><a href="/guide/components.html" class="sidebar-link">Component System</a></li>
            
                <li><a href="/guide/transitions.html" class="sidebar-link">Transitions</a></li>
            
                <li><a href="/guide/application.html" class="sidebar-link current">Building Larger Apps</a></li>
            
                <li><a href="/guide/extending.html" class="sidebar-link">Extending Vue</a></li>
            
                <li><a href="/guide/faq.html" class="sidebar-link">Common FAQs</a></li>
            
        </ul>
    </div>
</div>


<div class="content guide with-sidebar">
    <h1>Building Larger Apps</h1>
    <div id="ad">
        <script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=vuejs" id="_carbonads_js"></script>
    </div>
    <p>Vue.js is designed to be as flexible as possible - it’s just an interface library that doesn’t enforce any architectural decisions. While this can be very useful for rapid prototyping, it could be a challenge for those with less experience to build larger scale applications with it. The following is an opinionated perspective on how to organize larger projects when using Vue.js.</p>
<h2 id="Modularization">Modularization</h2><p>Although the standalone build of Vue.js can be used as a global, it is often better to utilize a modularized build system to better organize your code. The recommended approach of doing so is by writing your source code in CommonJS modules (the format used by Node.js, and also the format used by Vue.js source code) and bundle them using <a href="http://browserify.org/" target="_blank" rel="external">Browserify</a> or <a href="http://webpack.github.io/" target="_blank" rel="external">Webpack</a>.</p>
<p>Here are some build setup examples on GitHub:</p>
<ul>
<li><a href="https://github.com/vuejs/vue-browserify-example" target="_blank" rel="external">Vue + Browserify</a></li>
<li><a href="https://github.com/vuejs/vue-webpack-example" target="_blank" rel="external">Vue + Webpack</a></li>
</ul>
<h2 id="Single_File_Components">Single File Components</h2><p>In a typical Vue.js project we will be breaking up our code into many small components, and it would be nice to have each component encapsulate its CSS styles, template and JavaScript definition in the same place. A bonus for using the previously mentioned build tools is that they both provided mechanisms to transform the source code before bundling them together, and with a bit of pre-processing we can write our components like this:</p>
<p><img src="/images/vueify.png"></p>
<p>If you are into pre-processors, you can even do this:</p>
<p><img src="/images/vueify_with_pre.png"></p>
<p>This is achieved via using the <a href="https://github.com/vuejs/vueify" target="_blank" rel="external">Vueify</a> transform for Browserify, or with <a href="https://github.com/vuejs/vue-loader" target="_blank" rel="external">Vue-loader</a> for Webpack.</p>
<h2 id="Routing">Routing</h2><p>You can implement some rudimentary routing logic by manually listening on hashchange and utilizing a dynamic <code>v-component</code>.</p>
<p><strong>Example:</strong></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">div</span> <span class="attribute">id</span>=<span class="value">"app"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="title">div</span> <span class="attribute">v-component</span>=<span class="value">"&#123;&#123;currentView&#125;&#125;"</span>&gt;</span><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'home'</span>, &#123; <span class="comment">/* ... */</span> &#125;)</span><br><span class="line">Vue.component(<span class="string">'page1'</span>, &#123; <span class="comment">/* ... */</span> &#125;)</span><br><span class="line"><span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  data: &#123;</span><br><span class="line">    currentView: <span class="string">'home'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="comment">// Switching pages in your route handler:</span></span><br><span class="line">app.currentView = <span class="string">'page1'</span></span><br></pre></td></tr></table></figure>
<p>With this mechanism it’s very easy to leverage standalone routing libraries such as <a href="https://github.com/visionmedia/page.js" target="_blank" rel="external">Page.js</a> or <a href="https://github.com/flatiron/director" target="_blank" rel="external">Director</a>.</p>
<h2 id="Communication_with_Server">Communication with Server</h2><p>All Vue instances can have their raw <code>$data</code> directly serialized with <code>JSON.stringify()</code> with no additional effort. You can use any Ajax component you like, for example <a href="https://github.com/visionmedia/superagent" target="_blank" rel="external">SuperAgent</a>. It also plays nicely with no-backend services such as Firebase.</p>
<h2 id="Unit_Testing">Unit Testing</h2><p>Anything compatible with a CommonJS-based build system works. A recommendation is using the <a href="http://karma-runner.github.io/0.12/index.html" target="_blank" rel="external">Karma</a> test runner together with its <a href="https://github.com/karma-runner/karma-commonjs" target="_blank" rel="external">CommonJS pre-processor</a> to test your code modularly.</p>
<p>The best practice is to export raw options / functions inside modules. Consider this example:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// my-component.js</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  template: <span class="string">'&lt;span&gt;&#123;&#123;msg&#125;&#125;&lt;/span&gt;'</span>,</span><br><span class="line">  data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">      msg: <span class="string">'hello!'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  created: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'my-component created!'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>You can use that file in your entry module like this:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line"><span class="keyword">var</span> Vue = <span class="built_in">require</span>(<span class="string">'vue'</span>)</span><br><span class="line"><span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  data: &#123; <span class="comment">/* ... */</span> &#125;,</span><br><span class="line">  components: &#123;</span><br><span class="line">    <span class="string">'my-component'</span>: <span class="built_in">require</span>(<span class="string">'./my-component'</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>And you can test that module like this:</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Some Jasmine 2.0 tests</span></span><br><span class="line">describe(<span class="string">'my-component'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;  </span><br><span class="line">  <span class="comment">// require source module</span></span><br><span class="line">  <span class="keyword">var</span> myComponent = <span class="built_in">require</span>(<span class="string">'../src/my-component'</span>)</span><br><span class="line">  it(<span class="string">'should have a created hook'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    expect(<span class="keyword">typeof</span> myComponent.created).toBe(<span class="string">'function'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">  it(<span class="string">'should set correct default data'</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    expect(<span class="keyword">typeof</span> myComponent.data).toBe(<span class="string">'function'</span>)</span><br><span class="line">    <span class="keyword">var</span> defaultData = myComponent.data()</span><br><span class="line">    expect(defaultData.message).toBe(<span class="string">'hello!'</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p class="tip">Since Vue.js directives react to data updates asynchronously, when you are asserting DOM state after changing the data, you will have to do so in a <code>Vue.nextTick</code> callback. Alternatively you can set <code>Vue.config.async = false</code> during tests, so you can assert the DOM state synchronously right after the data change.</p>

<h2 id="An_Example">An Example</h2><p>The <a href="https://github.com/yyx990803/vue-hackernews" target="_blank" rel="external">Vue.js Hackernews Clone</a> is an example application that uses Webpack + vue-loader for code organization, Director.js for routing, and HackerNews’ official Firebase API as the backend. It’s by no means a big application, but it demonstrates the combined usage of the concepts discussed on this page.</p>

    <div class="footer">Caught a mistake or want to contribute to the documentation? <a href="https://github.com/vuejs/vuejs.org" target="_blank">Fork this site on Github</a>!</div>
</div>
                
            </div>
            <script src="/js/smooth-scroll.min.js"></script>
            <script src="/js/common.js"></script>
        
    </body>
</html>